/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.inspur.edp.lcm.metadata.extend.action;

import com.inspur.edp.lcm.metadata.api.entity.DbConnectionInfo;
import com.inspur.edp.lcm.metadata.api.entity.DeploymentContext;
import com.inspur.edp.lcm.metadata.api.service.FileService;
import com.inspur.edp.lcm.metadata.common.FileServiceImp;
import com.inspur.edp.lcm.metadata.common.Utils;
import com.inspur.edp.lcm.metadata.common.util.process.ProcessUtilFactory;
import com.inspur.edp.lcm.project.deployer.spi.DeployAction;
import com.inspur.edp.metadata.rtcustomization.serverapi.MetadataDeployService;
import io.iec.edp.caf.commons.runtime.CafEnvironment;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.io.*;
import java.util.Arrays;
import java.util.Objects;

@Slf4j
public class DeployActionImpl implements DeployAction {
    @Override
    public void deploy(DeploymentContext context) {
        log.info("开始交付物部署。");
        // 文件迁移，包含jar和web，元数据包入库
        FileService fileService = SpringBeanUtils.getBean(FileService.class);
        String serverPath = context.getDebugEnvironment().getServerPath();
        // 获取目录，应为server、metadata、web
        File publishFile = new File(context.getPublishPath());
        File[] dirs = publishFile.listFiles(File::isDirectory);
        if (Arrays.stream(dirs).noneMatch(dir -> dir.getName().equals(Utils.getServerPath()))) {
            log.info("无jar文件，不进行jar部署。");
        }
        if (Arrays.stream(dirs).noneMatch(dir -> dir.getName().equals(Utils.getMetadataProjPath()))) {
            log.info("无元数据文件，不进行元数据包部署。");
        }
        if (Arrays.stream(dirs).noneMatch(dir -> "web".equals(dir.getName()))) {
            log.info("无web文件，不进行web部署。");
        }

        for (File dir : dirs) {
            // jar包
            if (dir.getName().equals(Utils.getServerPath())) {
                // serverPath是否包含jstack或者server
                String server = FileServiceImp.combinePath(serverPath, "jstack");
                if (!new File(server).exists()) {
                    server = FileServiceImp.combinePath(serverPath, "server");
                    if (!new File(server).exists()) {
                        throw new RuntimeException("无法找到jar包目录：" + serverPath);
                    }
                }
                // copy
                fileService.folderCopy(dir.getAbsolutePath(), server);
                log.info("部署jar包交付物完成。");
            }
            // web
            if (dir.getName().equals("web")) {
                // copy
                String web = FileServiceImp.combinePath(serverPath, "web");
                fileService.folderCopy(dir.getAbsolutePath(), web);
                log.info("部署web交付物完成。");
            }
            // 元数据包
            if (dir.getName().equals(Utils.getMetadataProjPath())) {
                // 入库
                boolean isDeployTool = new File(FileServiceImp.combinePath(CafEnvironment.getStartupPath(), "lcm-project-deploy-tool.jar")).exists();
                DbConnectionInfo dbConnectionInfo = context.getDebugEnvironment().getDbConnectionInfo();
                // 当前环境，并且不是在工程部署工具中
                if (dbConnectionInfo == null || (StringUtils.isEmpty(dbConnectionInfo.getDbServerIP()) && !isDeployTool)) {
                    MetadataDeployService metadataDeployService = SpringBeanUtils.getBean(MetadataDeployService.class);
                    metadataDeployService.deployMetadata(dir.getAbsolutePath());

                    continue;
                }
                // 其他环境，或者在工程部署工具中
                String metadataDir = FileServiceImp.combinePath(Utils.getBasePath(), "tools/deploy/metadata/runtime");

                String javaHome = ProcessUtilFactory.getProcessUtil().getJavaHome();
                String javaCmd = Objects.equals(javaHome, "") ? "java" : javaHome + "/bin/java";

                String businessDatabase = "1";
                String notSync = "1";
                String isPatchAssembly = "0";
                //路径加上双引号，兼容路径含有空格的情况
                String command = javaCmd + " -Dloader.path=./libs,./3rd -Dspring.config.location=../config/application.yaml "
                        + "-jar metadata-deploy.jar "
                        + '\"' + dir.getAbsolutePath() + '\"' + " " + dbConnectionInfo.getDbType().toString() + " " + dbConnectionInfo.getUrl() + " " + dbConnectionInfo.getDbUserName() + " " + dbConnectionInfo.getDbPassword()
                        + " " + businessDatabase + " " + notSync + " " + isPatchAssembly;
                exec(command, new File(metadataDir));
                log.info("部署元数据交付物完成。");
            }
        }
        log.info("交付物部署完成。");
    }

    private void exec(String command, File dir) {
        Process pro;
        Runtime runTime = Runtime.getRuntime();
        if (runTime == null) {
            throw new RuntimeException("获取runTime为null");
        }
        try {
            pro = runTime.exec(command, null, dir);
            BufferedReader input = new BufferedReader(new InputStreamReader(pro.getInputStream()));
            PrintWriter output = new PrintWriter(new OutputStreamWriter(pro.getOutputStream()));
            String line;
            StringBuilder stringBuilder = new StringBuilder();
            String lineStr = System.getProperty("line.separator");
            boolean exceptonCatched = false;
            while ((line = input.readLine()) != null) {
                //记录日志
                if (line.contains("部署报错")) {
                    exceptonCatched = true;
                }
                if (exceptonCatched) {
                    stringBuilder.append(line);
                    stringBuilder.append(lineStr);
                }
            }
            input.close();
            output.close();
            pro.destroy();
            if (exceptonCatched) {
                throw new RuntimeException(stringBuilder.toString());
            }
        } catch (IOException ex) {
            //记录日志
            throw new RuntimeException("命令行调用元数据部署工具出错", ex);
        }
    }
}
